#ifndef __DEVMODBUSDEAL_H__
#define __DEVMODBUSDEAL_H__

#include "GDDevBase.h"
#include "Comm.h"
#include "ProxyUnit_DL645.h"
#define INV_WRITEBUF  24//645一包数据,除去数据的长度
#define N0_CONTRIL  0xffff //不控制时间段
#define MAX_COM_PORT_COUNT 2 //最多支持多少个串口
#define PROTC_MODBUSMT_BROADADDR		0


typedef struct
{
    u8 data[32];  
    u8 len; 
}Reg_Value_Type;


typedef struct{
    u8 reg_flag;
    u8 functype; //功能码类型, 1：读功能码，2：写功能码
} Reg_Send_Info;



//new===========================
typedef enum //消息类型
{
    MT_NULL,    //空消息
    MT_DLT645_EXCHANGE_MUDBUS, //645与modbus互转
    MT_AUTOFIND_DEV, //自发现设备搜索
}MsgType;
//end new========================



// typedef struct{
// 	bool bEnable; //下面的信息是否有效
// 	u16 addr;
// 	u8 manufacturer[32];
// 	u16 version;
// 	u8 port;
// }Dev_Version;



//设备档案结构体
typedef struct
{
	u8 	 addr;								
    char manufacturer[32];
    u16  version; 
    u8   port;
	u8   devType;              //设备类型， 1：逆变器，2：开关 
}Dev_Recode_Type;



typedef struct
{
    u8 status;          //状态
    // u8 funcode;
    u8 function;        //读，写

    u8 curFuncType;      //当前功能码类型, 1：读功能码，2：写功能码

    u8 devNum;          //设备序号
    
    u8 typeItem;        //类型项，区分哪个DI
    //写数据
    u8 data[200];   

    u16 setdata;        //例如无功功率调节，要开对应模式，要发一个对应模式,这里是针对模式的，因为会发两段，和时间发送的要隔开
    
    u8 recflag;         //回复标志,应答645

    u32 SendTicker;
    
    MsgType msgtype; // MT_DLT645_EXCHANGE_MUDBUS:PLC下发的消息，MT_AUTOFIND_DEV:设备自发现消息

    Dev_Recode_Type dv;  //设备厂商和版本
    
    Reg_Send_Info regs[max_num];
    u16 regsSize; //缓存大小

    Reg_Send_Info regsHaveSend[max_num];  //缓存已经接收到的全部寄存器数据
    u16 regsHaveSendSize; //缓存大小

    Reg_Send_Info regsNextSend[max_num];
    u16 regsNextSendSize; //缓存大小

    Reg_Value_Type regValue[max_num]; //缓存接收到的寄存器值    //按枚举来排序


}Send_Inverter_Frame_Type; //645接收特定DI需要传给状态机的数据，发送端

typedef struct 
{
    Send_Inverter_Frame_Type frame[inverterDEVMax]; //所有设备发送帧信息列表
    int frameCount; //所有设备发送帧信息列表数量
    int frameIndex; //当前发送帧索引
}All_Dev_Send_Frame;


typedef struct
{
    u8 ctrStartTime[6];     //开关起始时间 
    u8 p_StartTime[6];     //有功功率控制开始时间，值控制，百分比控制
    u8 q_StartTime[6];   //无功功率控制开始时间，值控制，百分比控制
    u8 pf_StartTime[6];      //功率因数开始时间，值控制，百分比控制
    u8 t_P_CtrStarTime[6];  //有功功率时间段控制开始时间，不区分值和百分比和开始结束控制，只确定发送控制的时间
    u8 aot_StarTime[6];    //通信异常事件异常开始时间
    u16 ticker;//光伏逆变器通信异常事件触发限值：监测间隔，
}Event_StartTime;



//时间用BCD的方式保存
typedef struct
{
	u16 firstStarAdjustTime;     //第一次调节的开始时间
    u16 firstEndAdjustTime;      //第一次调节的结束时间
    u32 firstSetActivePower;     //第一次调节有功功率值

    u16 secondStarAdjustTime;    //第二次调节的开始时间
    u16 secondEndAdjustTime;     //第二次调节的结束时间
    u32 secondSetActivePower;    //第二次调节有功功率值
    
}ActivePowerAd_Frame_Type;  //  有功功率时段调节数据块


typedef struct
{
	u16 firstStarAdjustTime;     //第一次调节的开始时间
    u16 firstEndAdjustTime;      //第一次调节的结束时间
    u16 firstSetPtActivePower;     //第一次调节有功功率百分比值

    u16 secondStarAdjustTime;    //第二次调节的开始时间
    u16 secondEndAdjustTime;     //第二次调节的结束时间
    u16 secondSetPtActivePower;    //第二次调节有功功率百分比值
    
}PtActivePowerAd_Frame_Type;  //  有功功率百分时段调节数据块

typedef struct
{
    u8  firstControlStatus;
    u8  secondControlStatus;

    u8  firstControlStatuspt;
    u8  secondControlStatuspt;
}ControlTimeFlag;


typedef struct//初始化直接不要放flash
{
    u32 startTime;  //检测开始时间  单位 hhmmss
    u32 endTime;   //检测结束时间  单位hhmmss
    u16 intervalTime; //间隔时间 单位min
    u8 dayMaxTime;   //日最大发生次数
}
AbnormalEvents_LimitType;//光伏逆变器通信异常事件触发限值


typedef struct
{
    u8      type;           //类型 u16 s16..
    float   tar;            //转化目标的单位
    float   src;            //源目标单元
    u8      outLen;         //输出长度，字节
}
Para_ChanType; //协议转换参数

typedef struct
{
    u16 voltage; //越限电压值
    u32 durationTime; //判定持续时间 单位s
}
OverVoltage_LimitType;//电压越限事件触发限值


typedef struct
{
		u8 ctroffsetCur;	//开关事件数据块偏移
		u8 ctrOffset;

		u8 p_offsetcur;		//有功功率控制事件数据块偏移
		u8 p_offset;

		u8 q_offsetCur;	//无功功率控制事件数据块偏移
		u8 q_offset;

		u8 pf_offsetCur;	//功率因数数据块偏移
		u8 pf_offset;


		u8 t_p_offsetCur;    //有功功率时段数据块偏移
		u8 t_p_offset;

        u8 aot_offsetCur;    //异常事件数据块偏移
		u8 aot_offset;

}Offset_page;


typedef struct
{
    u8 manufacturerNUM;    //厂家

    u16 conVersion;       //通讯版本

    u32 ratedActivePower;  //额定有功功率   //单位是整数 kw,即广东协议BCD转bin后的数据
    
    u32 ratedReactivePower; //额定无功功率

    u32 activePowerCtr;   //有功功率调节

    u32 reActivePowerCtr;   //无功功率调节

    u16 powerFactor;       //功率因数 

    u16 perActivePower;   //有功功率百分比
    
    u16 perReactivePower; //无功功率百分比

    ActivePowerAd_Frame_Type activePowerAdjust; //有功功率时段调节数据块

    PtActivePowerAd_Frame_Type  ptActivePowerAdjust; //有功功率百分比时段调节数据块

    ControlTimeFlag controlTimeFlag;

    AbnormalEvents_LimitType AbnormalEvents;//光伏逆变器通信异常事件触发限值

    OverVoltage_LimitType OverVoltage;      //电压越限事件触发限值

    u8 controlStatus;

    u8 controlType;//01 值控制有功功率，02百分比控制


}Intermediate_Frame_Type;

enum  //按时段控制方式
{
    NoControl,
    priceControl,   //值控制
    ptControl,      //百分比控制
};

enum inverterfun
{
    //变量类
    VOL_BLOCK = 1,                              //电压数据块                                                   
    
    CUR_BLOCK,                                  //电流数据块
    P_BLOCK,                                    //瞬时有功功率数据块
    Q_BLOCK,                                    //瞬时无功功率数据块
    FP_BLOCK,                                   //功率因数数据块
    ALL_BLOCK,                                  //变量的数据块

    //参数类
    RATA_P,                                     //额定有功功率
    RATA_Q,                                     //额定无功功率  
    OUT_TYPE,                                   //输出类型
    RunStatus,                                  //运行状态
    P_SET,                                      //有功功率调节
    Q_SET,                                      //无功功率调节
    PF_SET,                                     //功率因数调节
    P_PCT_SET,                                  //有功功率百分比调节
    Q_PCT_SET,                                  //无功功率百分比调节
    DEG,                                        //日发电量 
    T_P_SET,                                    //有功功率时段调节数据块
    T_P_PCT_SET,                                //有功功率百分比调节数据块
    // record,                                  //档案
    ExcepTrigLimit,                             //异常事件通讯测试
    VoltTrigLimit,                              //电压越限事件触发限值
    Switch_Status,                              //开关保护告警运行状态字
    YT_DATA,                                    //遥调数据
    
};      

enum ActiveControl  //有功功率控制状态
{
    WaitControl,          //等待控制
    firstControl,        //第一次控制
    firstEndControl,     //第一次结束控制

    SecondControl,      //第二次控制
    SecondEndControl,   //第二次结束控制

    firstControlPt,        //第一次控制，百分比
    firstEndControlPt,     //第一次结束控制，百分比

    SecondControlPt,      //第二次控制，百分比
    SecondEndControlPt,   //第二次结束控制，百分比

    Controling,         //控制中
    SuccessControl,     //完成控制块                                                                                      
}; 





typedef enum   //区间类型
{ 
    INTERVAL_ALLCLOSED,    // 闭区间 [min, max]
    INTERVAL_ALLOPEN,      // 开区间 (min, max)
    INTERVAL_FOBC,      // 前开后闭区间 (min, max]
    INTERVAL_FCBO,      //前闭后开区间 [min, max)
}IntervalType;

typedef struct //区间结构体
{
    // IntervalType type; //区间类型
    u32  min; //最小值
    u32  max; //最大值
}Interval;

typedef struct //区间集合结构体
{
    Interval ints[5]; //区间数组
    u8 count; //数组大小 
}IntervalSet;

typedef struct //枚举值集合结构体
{
    u16 values[10]; //枚举值数组
    u8 count; //数组大小
}EnumSet;

typedef union //枚举集合或区间集合联合体
{     
    IntervalSet intset; //区间集合
    EnumSet enumset; //枚举集合
}ValueRange;

typedef enum //值范围类型
{
    RANGE_ENUM, //枚举
    RANGE_INTERVAL, //区间
    // RANGE_NUll,       //无
}RangeType;

typedef struct //寄存器特征描述结构体
{ 
    u16 regaddr;  //寄存器地址，必须是一个寄存器地址
    RangeType rangetype; //范围值类型
    ValueRange range; //值范围
}RegDescriptor;

typedef struct //协议特征结构体
{

    Dev_Recode_Type archive; //设备档案信息，包含厂家、版本、设备类型等信息。

    bool isbroadcast; //是否支持广播
    u8 broadaddr; //广播地址   

    u8 minaddr; //最小单播搜索地址
    u8 maxaddr; //最大单播搜索地址

    RegDescriptor reg_desc1; //特征寄存器描述1
    RegDescriptor reg_desc2; //特征寄存器描述2
    RegDescriptor reg_desc3; //特征寄存器描述3
}ProtocolFeature;

typedef struct 
{
    ProtocolFeature broad_protocol_feature[MAX_REG_BANK_COUNT];//广播协议特征队列
    u16 broadsize; //广播协议特征队列大小

    ProtocolFeature single_protocol_feature[MAX_REG_BANK_COUNT];//单播协议特征队列
    u16 singlesize; //单播协议特征队列大小

}ProtocolFeatureQueue;



typedef struct { //当前协议结构体

    bool havefind; //是否搜索到对应协议
   // u8 comport; //通过哪个串口搜索

    bool broadactive; //广播搜索激活
    u8 broadindex;//广播协议特征队列的当前查找下标
    bool broadresp; //广播搜索是否有回应


    bool singleactive; //单播搜索激活
    u8 singleindex;//单播协议特征队列的当前查找下标

    ProtocolFeature* curfeature; //当前在查询的协议特征

    Dev_Recode_Type archive; //设备档案信息，包含厂家、版本、设备类型等信息。
    u8 curaddr; //当前地址，如果是广播搜索，则发送时保存广播地址，如果有回应，保存响应地址
    u8 comport; //通过哪个串口搜索
    // u8 manufacturer[32]; //找到对应协议后，保存厂家标识
    // u16 version; //找到对应协议后，保存版本号

} ActiveProtocol;

typedef struct { 
    bool isFirstStart;  //首次启动判断，用于开机启动判断, 只能修改一次。开机启动时初始化为true
    u8   check_count;   //首次启动，检查设备次数。开机启动时初始化为0
    u8   timeout_count; //正常业务消息超时次数。 开机启动时初始化为0
    bool havefind;      //是否搜索到对应协议。开机启动时初始化为true,因为开机时会通过指定逆变器档案进行检验，如果检验失败才开启搜索
    u8   comport;       //通过哪个串口搜索。开机启动时初始化为对应的端口号，未使用switchPort进行转换的端口。
    bool   ytFlag;       //需要获取遥调数据标志，645触发或者在档案对比正确后
    bool   ytgetFlag;    //端口已经获取到数据，在一次循环内就不需要再获取
} ComportSearchInfo;

//end new===========================

enum manufacturer  //厂家
{
    GROWATT=0,      //古瑞瓦特
    SUNGROW,        //阳光电源股份有限公司
    AISWEI, 	    //爱士惟新
    HUAWEI,         //华为技术有限公司
    TOPSCOMM,       //鼎信
    GinLong,        //锦浪
    MAX_manufacturer                                                                                      
}; 

enum Sendstaus//发送状态
{
    sendError,
    sendSuccess,
};



enum inverterDealStatus //逆变器处理状态
{
    Waiting,       //等待指令
    StartSend,     //由于645发起的第一包读数据
    ReceModbus,    //接收Modbus
    tickOut,        //等待超时
    Receok,         //接收完成
    dealFaild,          //失败
                    //目前先接收完成就发送，然后进入等待状态，后续考虑PLC模块，可能要增加

};


enum ctrResult      //光伏逆变器的开关机控制事件调控结果,广东协议
{
    gd_ctrSuccess,          //调控成功
    gd_ctrNone,             //未调控
    gd_ctrFailed,           //调控失败
    gd_NUll=0xff,                //无效
};

typedef struct
{
	struct TagDlt645Head
	{
		u8 bof;
		u8 adr[FRAME_ADDRLENGTH];
		u8 sbof;
		u8 ctl;
		u8 len;
	}head;
    u8 DI[4];
	u8 data[UART1_HARD_BUF_SIZE - FRAME_HEAD_SIZE-4];
}Dlt645_Inverter_Type;//为了处理方便在这加了DI

// enum modbusfun  //
// {
//     MB_FC_READ_COILS          = 0x01,     // 读取线圈状态
//     MB_FC_READ_DISCRETE_INPUTS= 0x02,     // 读取离散输入
//     MB_FC_WRITE_SINGLE_COIL    = 0x05,    // 写单个线圈
//     MB_FC_WRITE_MULTIPLE_COILS = 0x0F,    // 写多个线圈

//     MB_FC_READ_HOLDING_REGS    = 0x03,    // 读取保持寄存器
//     MB_FC_READ_INPUT_REGS      = 0x04,    // 读取输入寄存器//只读
//     MB_FC_WRITE_SINGLE_REG     = 0x06,    // 写单个寄存器
//     MB_FC_WRITE_MULTIPLE_REGS  = 0x10,    // 写多个寄存器
                                                                                          
// };

enum
{
	MODBUS_FC_READREG = 3,					// 读单个/多个寄存器
	MODBUS_FC_READRINREG = 4,					// 读取输入寄存器
	MODBUS_FC_WCOIL = 5,					// 写单个线圈
	MODBUS_FC_WRSREG = 6,					// 写单个寄存器

	MODBUS_FC_WRMCOIL = 15,					// 写多个线圈
	MODBUS_FC_WRMREG = 16,					// 写多个寄存器 0x10
	MODBUS_FC_RDFILE = 20,					// 读文件 0x14
	MODBUS_FC_WRFILE = 21,					// 写文件 0x15

	MODBUS_FC_RDHAR = 33,					// 读谐波 0x21  谐波数据太多，单独设置一个功能码

	MODBUS_FC_READINFO = 70,				// 读内部寄存器 0x46
	MODBUS_FC_WRITEINFO = 71,				// 写内部寄存器 0x47

	// ------注意,modbus的功能码只能小于128,因为高位bit7是错误应答	

	MODBUS_FC_USER_FILETX = 0x41,			// 自定义文件传输，采用功能码0x41(10进制为65)，65 ~ 72为保留以备用户功能所用，留作用户功能的扩展编码 2019.08.23
	MODBUS_FC_USER_EVENT = 0x43,			// 自定义事件传输，采用功能码0x43(10进制为67)	

	MODBUS_FC_CALIB = 0x82,					// 自定义校准用	
};

typedef struct
{
  Dev_Recode_Type archive; //设备档案信息，包含厂家、版本、设备类型等信息
  Recode_Type regs[40]; //寄存器地址点表
} Reg_Bank; //所有寄存器表



typedef struct
{
  Dev_Recode_Type g_InverterDevfile[inverterDEVMax]; 
} DEV_FILE_TEMP; //所有寄存器表


// extern Dev_Recode_Type g_InverterDevfile[inverterDEVMax]; 

extern Send_Inverter_Frame_Type invSendFrame;
extern Reg_Bank g_reg_bank[MAX_REG_BANK_COUNT]; 
extern Dlt645_Inverter_Type PLCResData;
extern Dev_Recode_Type g_InverterDevfile[inverterDEVMax];
extern Intermediate_Frame_Type  intermediateDev[inverterDEVMax];
extern All_Dev_Send_Frame g_allDevSendFrame;




void Inverter645_Init();
void Inverter_Service();
void ReadTime(u16 time,u8*dataBuf);
u8 Getoffsetvalue(u8 cur,u8 page,u8 len);
s8 SendMessageDeal();//Dev_Recode_Type *g_inverterDev,u8 devFun,u8 devNum,u8 getfun,u8 page);
u8 ProModbusInver_UnpackFrm(COMM_CTRL_TYPE *pCommCtrl);
// Dev_Version GetDevVersion(u8 devNum);
u8 checkRegvaild(Dev_Recode_Type *archive,u8 typeitem);
void InsertAndSortActiveReg_rd(Reg_Bank* regbank, u8 regIndex);
void InsertAndSortActiveReg_wr(Reg_Bank* regbank, Reg_Send_Info regIndex);
void getyeartosecond(u8 *src);
u8 insertSendRegCache_wr(Dev_Recode_Type *archive, Reg_Send_Info *pRegArray,u16 size);
bool insertSendRegCache_rd(Dev_Recode_Type *archive, u8 *pRegArray, u16 size);
Dev_Recode_Type chooseDev(u8 devNum);
int CheckFeatureReg_Singlecast();
int CheckFeatureReg_Broadcast();
Reg_Bank* FindRegBank(Dev_Recode_Type *archive);
void binToArryBig(u32 val,u8*Arry,u8 len);
void InsertAndSortActiveRegForAllDev_rd(Send_Inverter_Frame_Type *frame, Reg_Bank* regbank, u8 regIndex);
void InsertAndSortActiveRegForAllDev_wr(Send_Inverter_Frame_Type *frame, Reg_Bank* regbank, Reg_Send_Info regIndex);
u8 insertSendRegCacheForAllDev_wr(Send_Inverter_Frame_Type *frame, Dev_Recode_Type *archive, Reg_Send_Info *pRegArray,u16 size);
u8 insertSendRegCacheForAllDev_rd(Send_Inverter_Frame_Type *frame, Dev_Recode_Type *archive, u8 *pRegArray, u16 size);
bool sendNextDevFrame();

#endif
